import { ChangeDetectorRef, Component, inject, Input, OnInit } from '@angular/core';
import { AbstractControl, AsyncValidatorFn, FormBuilder, FormControl, FormGroup, ValidationErrors, Validators } from '@angular/forms';
import { map, Observable, Observer, of } from 'rxjs';

import { AdminUser, AdminUserService } from '@app/core/services/http/admin-user/admin-user.service';
import { DeptService } from '@app/core/services/http/system/dept.service';
import { Role, RoleService } from '@app/core/services/http/system/role.service';
import { ValidatorsService } from '@app/core/services/validators/validators.service';
import { SharedModule } from '@app/shared/shared.module';
import { fnCheckForm } from '@app/utils/tools';
import { fnAddTreeDataGradeAndLeaf, fnFlatDataHasParentToTree } from '@app/utils/treeTableTools';
import { BasicConfirmModalComponent } from '@app/widget/base-modal';
import { environment, localUrl } from '@env/environment.prod';
import { NzTreeNodeOptions } from 'ng-zorro-antd/core/tree';
import { NzSafeAny } from 'ng-zorro-antd/core/types';
import { NzMessageService } from 'ng-zorro-antd/message';
import { NZ_MODAL_DATA, NzModalRef } from 'ng-zorro-antd/modal';
import { NzSwitchModule } from 'ng-zorro-antd/switch';
import { NzTagModule } from 'ng-zorro-antd/tag';
import { NzTreeSelectModule } from 'ng-zorro-antd/tree-select';
import { NzUploadFile } from 'ng-zorro-antd/upload';

@Component({
  selector: 'app-user-modal',
  standalone: true,
  imports: [SharedModule, NzTreeSelectModule, NzTagModule, NzSwitchModule],
  templateUrl: './user-modal.component.html',
  styleUrl: './user-modal.component.less'
})
export class UserModalComponent extends BasicConfirmModalComponent implements OnInit {
  isSpinningAdd: boolean = false;
  isEdit!: boolean;
  validateForm!: FormGroup;
  readonly nzModalData: AdminUser = inject(NZ_MODAL_DATA);
  roleOptions: Role[] = [];
  avatarUrl: string = '';
  uploading: boolean = false;
  deptNodes: NzTreeNodeOptions[] = [];
  imgActionUrl: string = '';
  constructor(
    private readonly fb: FormBuilder,
    private readonly adminUserService: AdminUserService,
    private readonly messageService: NzMessageService,
    private readonly validatorService: ValidatorsService,
    private readonly roleService: RoleService,
    private readonly ref: ChangeDetectorRef,
    override modalRef: NzModalRef,
    private readonly cdr: ChangeDetectorRef
  ) {
    super(modalRef);
  }

  protected getCurrentValue(): Observable<NzSafeAny> {
    if (!fnCheckForm(this.validateForm) || !this.validateForm.controls['password'].valid || !this.avatarUrl) {
      return of(false);
    }
    return of({ ...this.validateForm.value, avatar: this.avatarUrl, deactivated: !this.validateForm.controls['deactivated'].value });
  }

  get passwordFormField(): AbstractControl<NzSafeAny> | null {
    return this.validateForm.get('password');
  }

  phoneDuplicateValidate: AsyncValidatorFn = (control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
    if (!control.value) {
      return Promise.resolve({ required: true });
    }

    let filterParams = `eq(Phone,${control.value})`;
    if (this.nzModalData?.id) {
      filterParams += `&noteq(Id,${this.nzModalData.id})`;
    }

    return this.adminUserService.getEntityList({ '@filter': `${filterParams}` }).pipe(
      map(exist => {
        const validationErrors: ValidationErrors = { duplicate: exist.length > 0, message: '手机号已存在！' };
        return validationErrors;
      })
    );
  };

  userNameDuplicateValidate: AsyncValidatorFn = (control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
    if (!control.value) {
      return Promise.resolve({ required: true });
    }

    let filterParams = `eq(UserName,${control.value})`;
    if (this.nzModalData?.id) {
      filterParams += `&noteq(Id,${this.nzModalData.id})`;
    }

    return this.adminUserService.getEntityList({ '@filter': `${filterParams}` }).pipe(
      map(exist => {
        if (exist.length > 0) {
          const validationErrors: ValidationErrors = { duplicate: exist, message: '用户名已存在！' };
          return validationErrors;
        }

        return null;
      })
    );
  };

  beforeUpload = (file: NzUploadFile, _fileList: NzUploadFile[]): Observable<boolean> =>
    new Observable((observer: Observer<boolean>) => {
      const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
      if (!isJpgOrPng) {
        this.messageService.error('You can only upload JPG file!');
        observer.complete();
        return;
      }
      const isLt1M = file.size! / 1024 / 1024 < 1;
      if (!isLt1M) {
        this.messageService.error('图片必须小于2MB!');
        observer.complete();
        return;
      }
      observer.next(isJpgOrPng && isLt1M);
      observer.complete();
    });

  private getBase64(img: File, callback: (img: string) => void): void {
    const reader = new FileReader();
    reader.addEventListener('load', () => callback(reader.result?.toString() ?? ''));
    reader.readAsDataURL(img);
  }

  handleChange(info: { file: NzUploadFile }): void {
    switch (info.file.status) {
      case 'uploading':
        this.uploading = true;
        break;
      case 'done':
        // Get this url from response in real world.
        this.getBase64(info.file.originFileObj!, (img: string) => {
          this.uploading = false;
          this.avatarUrl = info.file.response.items[0].serverfilepath;
          this.ref.detectChanges();
        });
        break;
      case 'error':
        this.messageService.error('Network error');
        this.uploading = false;
        break;
    }
  }

  getRoleList(): Promise<void> {
    return new Promise<void>(resolve => {
      this.roleService.getEntityList().subscribe(records => {
        this.roleOptions = records;
        resolve();
      });
    });
  }

  initForm(): void {
    this.validateForm = this.fb.group({
      username: new FormControl('', {
        asyncValidators: [this.userNameDuplicateValidate],
        validators: [Validators.required]
      }),
      password: ['', [Validators.required, this.validatorService.passwordValidator()]],
      avatar: ['', Validators.required],
      deactivated: ['', Validators.required],
      roleids: [[], Validators.required],
      phone: ['', [this.validatorService.mobileValidator()]]
    });

    if (this.nzModalData) {
      this.avatarUrl = this.nzModalData.avatar;
      this.cdr.detectChanges();
    }
  }

  async ngOnInit(): Promise<void> {
    this.initForm();
    this.isEdit = !!this.nzModalData;
    this.imgActionUrl = environment.production ? `/daemonApi/upload/upload` : `${localUrl}/upload/upload`;
    await Promise.all([this.getRoleList()]);
    if (this.isEdit) {
      this.validateForm.patchValue({ ...this.nzModalData, avatar: this.nzModalData.avatar ?? '', deactivated: !this.nzModalData.deactivated });
    }
  }
}
